- 1. Docker简介
- 2.镜像的基本命令
- 3.容器的基本命令
- 4.常用其他命令
- 5.命令小结
- 6. 小实战
- 7.提交镜像
- 8.容器数据卷
- 9.Dockfile
- 10.发布自己的镜像
- 11. Docker网络
- 12.Docker工具安装
- 13.常用容器
1. Docker简介
Docker是一种虚拟化技术,类比于虚拟机。虚拟机的使用需要安装操作系统并在操作系统上安装软件才能使用。虚拟机上的软件需要消耗系统的资源的时候,由虚拟机的操作系统向宿主机的操作系统申请.而Docker是共用宿主机的内核,而且各个容器之间是操作系统级别隔离的,每个容器都只安装了最小的运行环境.Dockre是比虚拟机更加轻量的虚拟技术。
Docker优势:
1.将应用程序和运行环境一起打包,保持一致的运行环境,轻松迁移
2.对进程进行封装隔离,容器与容器之间互不影响
1.1 基本概念
镜像image
Docker镜像就好比是一个软件安装包,通过这个镜像可以创建容器,一个镜像可以创建多个容器.
比如,一个tomcat镜像 -> docker run -> tomcat容器(提供服务)。
一个镜像可以创建多个tomcat容器,相当于通过一个软件包安装了多个tomcat,每个容器之间互不影响.
容器Container
Docker利用容器技术,独立运行一个或一组应用。
容器是通过镜像来创建的。
仓库Repository
仓库就是存放镜像的地方。分为公有仓库和私有仓库。
DockerHub(国外),阿里云(国内,配置镜像加速)
1.2 安装Docker
- 查看环境
查看Linux版本,系统内核要求3.10以上:
1 | uname -a |
1 | Linux ming 3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux |
查看系统信息:
1 | cat /etc/os-release |
1 | NAME="CentOS Linux" |
- 安装Docker
如果已经安装过docker,卸载已经安装的版本
1 | sudo yum remove docker \ |
设置Docker的仓库
1 | 1. 下载yum-utils(其中包含了yum-config-manager) |
安装Docker
1 | 清除缓存 |
查看Docker版本信息
1 | docker version |
出现以下结果,说明Docker安装成功。
1 | Client: Docker Engine - Community |
启动docker
1 | sudo systemctl start docker |
运行hello-world示例镜像
1 | sudo docker run hello-world |
1.3 阿里云镜像加速器
登录阿里云,找到容器镜像服务
,镜像加速器。
1.4 docerk run 流程
1.5 底层原理
Docker是怎么工作的?
Docker是一个Client-Server结构的系统,Docker的守护进程运行在服务器上,客户端通过Socket访问,
Docker Server接收到Docker Client的指令,就会执行这个命令。
2.镜像的基本命令
2.1 查看版本
1 | 显示docker版本 |
2.2 查看镜像
1 | 1. 查看所有镜像 |
2.2 搜索镜像
搜索镜像可以使用DockerHub搜索,也可以使用命令进行搜索。
1 | 1. 搜索mysql的镜像 |
2.3 下载镜像
1 | 1. 不指定版本,默认下载最新版本latest |
既然知道了真实地址,docker pull mysql:5.7 相当于 docker pull docker.io/library/mysql:5.7
2.4 删除镜像
如果有容器使用了镜像,即使容器没有启动,删除镜像之前也需要将对应的容器删除.当然可以使用-f强制删除.
1 | 1.通过镜像名称删除,-f 强制删除 |
2.5 导出镜像
-o 指定输出文件
1 | [root@aliyun ~]# docker import tomcat.tar mytomcat:01 |
2.6 导入镜像
1 | [root@aliyun ~]# docker import tomcat.tar mytomcat:01 |
3.容器的基本命令
3.1 创建容器并启动
有些容器在使用Dockerfile构建镜像的时候,Dockerfile中可能就已经存在了CMD指令.
比如以-it交互模式启动centos容器时,默认执行的CMD指令是 /bin/bash.
当然,可以在启动容器的时候覆盖默认的CMD指令
1 | 查看centos:7镜像创建的过程,能发现默认的CMD指令是/bin/bash |
进入容器后,主机名称变成了容器id.
如果在启动容器的时候没有通过–name指定容器的名称,Docker会自动生成一个随机的容器名称.
1 | 进入容器后,主机名称变成了容器id |
3.2 查看容器
1 | 1. 查看正在运行的容器 |
3.3 退出容器
1 | 1. 退出容器并关闭 |
3.4 删除容器
删除容器使用rm,删除镜像使用rmi。(i = image)
1 | 1. 指定容器id删除 |
3.5 启动和停止容器
1 | 1. 启动容器 |
3.6 查看容器日志
1 | docker logs 容器id |
3.7 导出容器
1 | root@aliyun ~]# docker ps |
3.8 导入容器
1 | 第一种写法 |
用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库.
这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大.
此外,从容器快照文件导入时可以重新指定标签等元数据信息
4.常用其他命令
4.1 后台启动容器
1 | docker run -d 镜像名称 |
1 | 问题:后台方式启动容器后,docker ps查看容器,发现刚启动的容器停止了? |
4.2 查看日志
1 | 查看容器7194f420dccf最近10行的日志信息 |
为了方便查看日志,启动容器的时候让它运行脚本:
1 | 后台方式启动,每隔1s输出hello,world,方便查看日志信息 |
4.3 查看容器中进程的信息
1 | 1. 查看容器中进程信息 |
4.4 查看镜像的元数据
1 | docker inspect 容器id |
1 | [ |
4.5 进入当前正在运行的容器
1 | 1. 进入当前正在运行的容器进行操作,不会启动新的进程 |
虽然是不同的进程进行操作,但容器内的资源还是共享的。
首先使用docker exec -it 4db8b5f683c1 /bin/bash进入容器:
然后使用docker attach 4db8b5f683c1进入容器:并没有启动一个新的/bin/bash进程。
4.6 从容器内拷贝文件到主机上
1 | 即使容器当前不在运行,也可以拷贝出文件 |
1 | [root@ming local]# docker cp 4db8b5f683c1:/aaa.txt /home/ # 将容器内/aaa.txt 拷贝到当前主机 /home/ 目录下 |
5.命令小结
6. 小实战
6.1 部署nginx
1 | 1. 下载nginx |
外网访问http://47.96.224.198:3344/,容器内启动nginx成功。
6.2 部署tomcat
1 | 1. 查看镜像 |
外网访问http://47.96.224.198:3355/,出现以下界面:
这是因为阿里云镜像默认是下载最小的镜像,只下载了必要的组件。
1 | root@5e2e3cb50a29:/usr/local/tomcat# ls |
再次访问[http://47.96.224.198:3355/,这次就可以正常访问了。
7.提交镜像
从仓库下载下来的镜像都是只读的,每当我们操作镜像,就会在原来镜像的上面加一层我们自己的操作,我们可以将它保存起来,下次直接使用我们操作过的镜像。
1 | 1. 查看镜像 |
1 | 将镜像89b24a4b7084提交,生成我们自己的镜像mytomcat |
8.容器数据卷
我们在容器内操作,数据保存在容器内,这是一件很危险
的事情,假如不小心删除了容器,容器内的数据就全部丢失了。
有没有一种技术可以将容器内的数据同步到宿主机器上,将容器内的目录和宿主机的目录进行绑定,无论修改容器内的目录,还是修改宿主机的目录,都能自动同步数据,完成数据的持久化呢? 这就是数据卷的技术。
使用以下命令完成数据卷的挂载:
1 | docker run -v 宿主机的目录:容器内的目录 |
1 | 1. 进入容器,进行目录挂载 |
8.1 部署mysql
1 | 1. 直接使用docker run 下载mysql,如果本地不存在mysql的镜像,会从远程仓库中拉取 |
8.2 具名挂载和匿名挂载
之前使用的docker run -v 宿主机的目录:容器内的目录
是指定目录的挂载方式。
除此之外,还有具名挂载和匿名挂载。
具名挂载
具名挂载通过docker run -v 卷名:容器内的目录
进行挂载。
1 | 1. 具名挂载的方式启动nginx |
匿名挂载
匿名挂载通过docker run -v 容器内路径
进行挂载。
1 | 1. 匿名挂载的方式启动nginx |
我们发现,如果不是以指定目录的方式进行挂载,挂载的目录默认是在/var/lib/docker/volumes/卷名/_data/
目录下。
8.3 权限
相对于容器内而言,默认情况下,文件是可读可写的。
1 | 1. 启动nginx容器并进入容器 |
我们可以在启动容器的时候,指定容器内的文件权限:
1 | 1. ro = read only ,在容器内只读,不能修改 |
8.4 多个容器挂载同一个目录
使用–volume-for指定一个容器,同步这个容器的数据。就相当于,继承一个容器,自动同步它的数据。
1 | 1. 启动容器centos1,挂载容器内的目录/home/centos1 |
接下来,我们创建一个新的容器centos3,让它–volumes-from centos2,它能不能自动同步centos2创建的目录centos2呢?
1 | 1. 启动centos3容器 |
8.5 Macos数据卷挂载目录
Macos系统中,Docker与宿主机之间多了一层Linux,无法直接查看数据卷挂载的目录.
可以重新创建一个Debian的Linux虚拟机,在/var/lib/docker/volumes/
目录下可以查看docker挂载的数据卷.
1 | 拉取了一个debian的镜像 |
9.Dockfile
我们可以使用Docker官方(或其他人)编写的镜像.也可以使用Dockerfile创建自己的镜像.我们以后要发布项目,就需要编写dockfile文件.
9.1 制作Dockefile
dockerfile就是一个脚本文件,里面的脚本用来创建镜像.
dockerfile文件的命名官方推荐为Dockerfile
.
Dockerfile文件所在的目录称为上下文目录
,当执行docker commit提交的时候,会将上下文路径的所有路径上传到Docker Server端.
所以,要么Dockerfile文件所在上下文目录存放的全部都是构建镜像所需要的文件,
要么添加Dockerignore文件描述构建镜像时需要忽略的文件.
需要注意的几点:
- 每个保留关键字(指令)都必须是大写字母
- 执行从上到下顺序执行
- 每一个指令都会创建提交一个新的镜像层,并提交
- 必须使用双引号,单引号不行
- Dockerfile的第一条指令必须是FROM
写好脚本文件后,使用docker build
命令生成镜像.
需要注意的几点:
- -t 生成的镜像名称不能带/
- 最后一个参数指定上下文路径,’.’代表当前所在目录
- 如果文件命名为Dockerfile,在docker build的时候可以不指定-f参数.否则可以通过-f指定Dockerfile文件所在的目录
1 | 1. 利用当前目录下的dockerfile文件在当前目录下生成xiaoming/centos的镜像 |
9.2 Dockfile指令
命令 | 描述 |
---|---|
FROM | 指定基础镜像,一切从这里开始构建 |
MAINTAINER | 指定维护者信息(姓名+邮箱) |
RUN | 镜像构建的时候需要运行的命令 |
ADD | 添加内容,会自动解压 |
WORKDIR | 镜像的工作目录 |
VOLUME | 设置卷,挂载主机目录 |
EXPOSE | 暴露端口配置 |
CMD | 指定容器启动的时候运行的命令,只有最后一个会生效 |
ENTRYPOINT | 指定这个容器启动的时候运行的命令,可以追加命令 |
ONBUILD | 当构建一个被继承Dockfile就会触发指令 |
COPY | 类似ADD,将文件拷贝到镜像中 |
ENV | 构建的时候设置环境变量 |
9.2.1 FROM
FROM 指令表明构建的镜像是基于FROM指定的这个镜像构建的.
Dockerfile的第一条指令就必须是FROM指令.
以后我们将自己的项目构建成一个容器的时候,比如需要JDK的开发环境,就应该基于一个包含JDK环境的镜像去构建.
1 | 当前目录下存在Dockerfile文件和hello.txt文件 |
9.2.2 RUN
RUN可以在创建镜像时执行命令.
1 | FROM centos:7 |
每一个RUN都是启动一个容器、执行命令、然后提交存储层文件变更.
第一层RUN cd /app
的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更.
而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化.
1 | RUN cd /app |
9.2.3 EXPOSE
EXPOSE声明容器对外暴露的端口,并不会在自动在宿主机上进行端口映射.
即使不声明也是可以在运行容器的时候进行端口映射的,但是遵守规范,还是在Dockerfile文件中声明一下.
如果在启动容器时使用随机端口映射(-P),会自动映射EXPOSE端口.
EXPOSE 指令可以声明多次.
1 | EXPOSE 8080 |
9.2.4 WORKDIR
WORKDIR 指定进入容器时的默认工作路径.
如果WORKDIR指定的目录不存在,会自动创建.
1 | WORKDIR /usr/local |
WORKDIR 可以声明多次.
如果每个WORKDIR指令声明的都是绝对路径,以最后一个绝对路径为准.
如果最后一个WORKDIR指令声明的是相对路径,会将多个WORKDIR的路径连接在一起.
1 | Dockerfile文件中声明多条WORKDIR指令,后面两条WORKDIR指令是相对路径 |
9.2.5 COPY
COPY 拷贝文件到容器内.
源路径(宿主机上的路径)只能写相对路径(一般都是在上下文目录中),不能写绝对路径.
1 | 绝对路径 |
源路径可以指定多个.
如果源路径为文件夹,复制的时候不是直接复制该文件夹,而是将文件夹中的内容复制到目标路径.
如果源路径为文件夹,目标路径以/结尾.
目标路径可以是相对路径,相对于WORKDIR的相对路径.
复制源路径的时候,源文件的用户|权限等信息都会保留,可以在CPOY指定–chown修改文件的所属用户和所属组.
1 | FROM tomcat |
9.2.6 ADD
ADD与COPY命令相似,它可以指定一个url,从url中下载文件到指定目录中.
下载的文件权限默认是600.可以使用RUN命令进行权限的调整.所以,还不如使用RUN + WGET(CURL)下载文件并处理好权限后再上传到容器中.
从远程的url中下载文件到容器中,并不会自动解压.
从上下文目录中上传文件到容器中,会自动进行解压.
1 | 下载yum的安装包到容器内的/usr/local/tomcat中 |
1 | 从上下文路径中上传tar包到容器内指定的目录 |
因此在COPY
和ADD
指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY
指令,仅在需要自动解压缩的场合使用ADD
.
9.2.7 VOLUME
VOLUME使用匿名挂载容器内的数据卷.
为了避免在启动容器的时候忘记挂载数据卷,可以在Dockerfile文件中指定VOLUME匿名挂载.当容器启动时,如果使用-d指定了数据卷挂载,Dockerfile中的VOLUME会被覆盖.
1 | dockerfile中挂载这两个目录 |
9.2.8 EMV
EMV 设置环境变量,在EMV指令之后的指令都可以通过$()来使用环境变量
1 | ENV MAINDIR /usr/local/tomcat |
9.2.9 CMD
CMD指令指定在容器启动时(docker run)执行的命令.
CMD指令有两种方式:
- shell模式: CMD ls /usr/local/tomcat 实际上会被包装成 CMD [“sh”,”-c”,”ls”,”/usr/local/tomcat”],由于sh的存在,可以使用环境变量.
- exec模式: CMD [“ls”,”/usr/local/tomcat”]
1
CMD ["ls","/usr/local/tomcat"]
当在Dockerfile指定了CMD指令的时候,可以在启动容器时覆盖CMD命令.
1 | CMD ["ls","-l"] |
9.2.10 ENTRYPOINT
ENTRYPOINT和CMD指令有着类似的功能.
1 | Dockerfile中指令 |
9.2.11 CMD|ENTRYPOINT区别
如果在Dockerfile文件中同时指定了CMD和ENTRYPOINT指令,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为ENTRYPOINT CMD
.
应用场景1: 在Dockerfile文件中指定ENTRYPOINT默认运行的命令,在启动容器的时候指定CMD指令,CMD指令会被当成ENTRYPOINT的参数,从而达到动态添加执行参数
的效果.
1 | Dockerfile中指令 |
应用场景2: 在Dockerfile文件中通过ENTRYPOINT指定通用的命令,在容器启动时指定CMD指令,CMD指令会被当成ENTRYPOINT的参数,从而达到动态传参
的效果.
比如在发布springboot项目的时候,运行java -jar 项目名,只是项目名称不同,执行的命令都是一致的,就可以使用这种方法来动态传参.
1 | CMD ["/usr/local/tomcat"] |
9.2.12 HEALTHCHECK
HEALTHCHECK指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态.
当在一个镜像指定了HEALTHCHECK指令后,用其启动容器,初始状态会为starting
,在HEALTHCHECK指令检查成功后变为healthy
,如果连续一定次数失败,则会变为unhealthy
.
HEALTHCHECK 支持下列选项:
–interval=<间隔>:两次健康检查的间隔,默认为30秒
–timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认30秒
–retries=<次数>:当连续失败指定次数后,则将容器状态视为unhealthy,默认3次
1 | 这里举个例子,也就是说每隔5s向hello.txt文件中打印一句'healthcheck' |
9.2.13 USER
USER指令切换用户,对后面的RUN等其他指令生效.
USER指定的用户必须存在.否则报错unable to find user test: no matching entries in passwd file.
1 | RUN groupadd -r tomcat && useradd -r tomcat -g tomcat |
9.3 查看构建过程
从镜像构造的过程来看,当执行docker build的时候,一条Dockerfile指令就对应着一层镜像层.
查看CREATED镜像层的创建时间可知,如果有共享的镜像层可以使用,则不会生成新的镜像层.
1 | 使用docker history 镜像id 可以查看一个镜像构建的过程 |
9.4 制作tomcat的Dockfile
准备tomcat,JDK的压缩包,编写Dockerfile
1 | 基于centos |
docker build 生成镜像文件
1 | 1. 由于文件命名是Dockerfile,无需指定-f参数 |
1 | echo "1">/proc/sys/vm/drop_caches |
9.5 不同操作系统的镜像
使用镜像创建容器,该镜像必须与Docker宿主机系统架构一致.为了在不同的操作系统上使用相同的镜像,就必须为每个操作系统单独构建一个镜像.
但是Docker官方提供了一个Manifest列表.
当用户获取一个镜像时,Docker引擎会首先查找该镜像是否有manifest列表,如果有的话Docker引擎会按照Docker运行环境(系统及架构)查找出对应镜像.如果没有的话会直接获取镜像.
9.5.1 查看manifest列表
使用docker manifest inspect
查看manifest列表.
1 | [root@aliyun ~]# docker manifest inspect golang:alpine |
10.发布自己的镜像
1 | 1. 首先需要创建DockerHub的账号 |
11. Docker网络
安装了docker之后,Docker默认使用桥接模式,会自动分配一个网卡docker0,我们可以通过以下命令查看:
1 | ➜ ~ docker network ls |
如果想查看网络的详细信息,可以使用docker network inspect ID
1 | ➜ ~ docker inspect bridge |
桥接模式使用veth-pair的技术(一对虚拟设备接口,一端连着容器,一端连着docker0,只要一端收到数据,另外一端也会接受到相同的数据).
当宿主机与容器通信时,宿主机往docker0的设备接口发送数据,连接着docker0的容器端的设备接口也会收到相同的数据.
当容器与宿主机通信时,容器往容器的设备接口发送数据,连接着容器的docker0端设备接口也会收到相同的数据.
而容器的IP与docker0的IP会在同一个网段,可以相互通信.这就实现了容器间的通信.
11.1 问题1:宿主机和容器能不能ping通? ✔
1 | 1. 查看宿主机器的ip addr |
11.2 问题2:两个容器直接能否直接ping通? ✔
1 | 1.再次启动一个容器tomcat2,查看ip地址 |
11.3 能否通过容器的name来连接? ×(–link ✔)
默认容器之间的通信使用的是IP的形式,如果想使用容器的名字来进行通信,需要在创建容器的时候指定–link参数.
需要注意的是–link参数是单向的.
–link参数实际上是在容器的/etc/hosts文件中增加了一个host的映射,当通过名称访问时,会被映射成对应的IP地址.
1 | 1. 进入到tomcat1容器,直接ping tomcat2容器的名字 |
虽然–link能使用容器名称来连接,但这种做法是过时的,更好的方法是使用自定义网络。
11.4 自定义网络
自定义一个网络
1 | 1. 创建网络,指定网关和子网掩码 |
11.5 网络互联
上面tomcat1和tomcat2已经连接在mynet网络下了,那么连接在docker0的容器,能否访问mynet网络下的容器呢?
1 | 1. 使用默认的docker0启动一个容器tomcat3 |
11.6 查看容器IP
11.6.1 在容器内查看
如果在容器内查看容器IP,可以查看/etc/hosts文件
1 | root@f1953dca10db:/etc# cat hosts |
11.6.2 在容器外查看
如果在容器外查看容器IP,可以使用docker inspect 容器id|name 查看容器的信息,其中有一个字段IPAddress就是容器IP
或者可以添加–format 只获取容器信息的IPAddress字段
1 | -f 表示format |
11.6.3 获取所有容器名称和IP
-f 参数必须使用单引号
1 | docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress}}' $(docker ps -aq) |
或者可以通过网桥查看所有连接到该网桥的容器的信息:
1 | 查看所有的网桥信息 |
11.7 Macos的网络问题
Docker For Mac的网络问题及解决办法
Docker官方对于MacOs网络的描述
Docker是利用Linux的Namespace和Cgroups来实现资源的隔离和限制,容器共享宿主机内核.所以Mac本身没法运行Docker容器.
Mac是在Macos上跑了一个Linux虚拟机,然后在虚拟机上跑的Docker.
这就导致Mac上没有Docker0的网桥,Mac上也不能直接ping通容器的IP.
解决方法(docker-connector):
1.(Macos端):在Mac上安装docker-connector,并修改docker-connector.conf添加bridge的IP
Mac上使用homebrew安装,安装后的默认路径是在/opt/homebrew
1 | brew install wenjunxiao/brew/docker-connector |
修改/opt/homebrew/etc/docker-connector.conf配置文件,添加需要访问容器的bridge:
1 | # 添加docker默认的bridge |
启动docker-connector服务:
1 | brew services start docker-connector |
2.(Docker端):拉取docker-connector镜像,并创建容器:
1 | docker run -it -d --restart always --net host --cap-add NET_ADMIN --name connector wenjunxiao/mac-docker-connector |
根据以上的配置,Mac宿主机就能ping通容器内IP了.
11.8 查看端口映射配置
1 | 查看tomcat容器所有的端口映射 |
12.Docker工具安装
12.1 vim
1 | apt-get update |
或者使用yum安装:
1 | yum install -y vim |
12.2 ping
1 | apt-get update |
12.3 ifconfig
1 | apt-get update |
12.4 yum
1 | wget http://yum.baseurl.org/download/3.2/yum-3.2.28.tar.gz |
13.常用容器
13.1 Mysql
使用别人镜像的时候,很重要的一点是到Docker Hub上查找镜像并查看镜像的使用方法.
主要是关于数据持久化或配置备份相关的目录,只有根据镜像的说明文档才知道它存放的路径在哪里.
后台启动mysql容器,挂载到docker的数据款mysqldata上,映射宿主机的3306端口,在macos上需要指定platform
-e参数是环境变量,指定mysql启动时root的密码
1 | docker run -d --name mysql -v mysqldata:/var/lib/mysql -p 3306:3306 --platform linux/amd64 -e MYSQL_ROOT_PASSWORD=root mysql |
容器启动之后查看mysql容器的信息,这里只列出基本信息和数据卷信息:
1 | ➜ bin docker inspect mysql |
13.2 tomcat
直接使用docker run启动一个容器,当本地没有tomcat的镜像时,会直接到远程仓库中拉取.
将容器内的webapps目录挂载到宿主机的/usr/local/apps目录中,以后项目只需要部署在宿主机的/usr/local/apps目录下.
将容器内的conf目录挂载到宿主机的/usr/local/confs目录中,以后tomcat的配置文件只需要修改/usr/local/confs目录下的配置文件.
1 | docker run -d --name tomcat -p 8080:8080 -v /usr/local/apps:/usr/local/tomcat/webapps -v /usr/local/confs :/usr/local/tomcat/conf tomcat:latest |
此时,通过宿主机IP:端口
是访问不到tomcat的.
查看容器内的webapps目录,发现其目录下是空的.同时发现有一个webapps.dist的目录,我们需要将webapps.dist目录下的所有文件移动或复制到webapps目录下,才可以通过外网访问.
1 | 移动webapps.dist下的所有文件到webapps |
完成复制的操作后,需要查看tomcat的启动日志,是否有重新加载了webapps的目录下的文件,如果还是加载webapps.dist目录的话,需要重启tomcat服务器.
关于修改tomcat的配置文件,如果修改的是tomcat不能重加载的配置,我们需要重新运行一个容器来修改tomcat的配置.
假设我们将tomcat的配置文件已经挂载到了宿主机上的/usr/local/confs/server.xml下,修改server.xml的tomcat的端口8080->8081
此时查看tomcat的日志,发现tomcat的端口还是8080,而不是8081,这是因为tomcat不能加载到tomcat端口改变的这个配置.
重启一下tomcat容器,查看日志如下:
1 | 18-Dec-2021 13:39:56.343 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8081"] |
日志显示,当前容器内的tomcat已经监听8081端口,宿主机上的8080映射容器内的8081端口.
但是当我们使用外网访问8080端口的时候,却访问不到.
此时,我们退出tomcat容器,在宿主机上查看当前运行的tomcat容器信息:
1 | [root@aliyun ~]# docker ps |
我们可以发现,即使容器内的tomcat已经运行在8081端口,但是这个容器启动的时候,也就是执行docker run命令的时候,就已经指定了
-p 8080:8080,即使容器内的tomcat修改了端口,这个映射没有修改,也无法通过8081端口访问到tomcat.
此时,我们可以重新启动一个容器,使用原来的webapps和confs,修改端口映射为宿主机8080->容器8081
1 | docker run -d --name tomcat1 -p 8080:8081 -v /usr/local/apps:/usr/local/tomcat/webapps -v /usr/local/confs:/usr/local/tomcat/conf tomcat |
此时,查看启动的容器:
端口映射已经修改为8080->8081,而webapps和confs因为之前已经被挂载到了宿主机持久化了,再次启动一个新的容器的时候挂载的数据和原来的一致,只是端口的映射修改了.
此时,通过外网访问8080端口,能正常访问到容器内的8081端口.
1 | [root@aliyun _data]# docker ps |